package com.example.satoken.handler;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.hutool.core.collection.CollUtil;
import com.example.satoken.annotion.BaseResponse;
import com.example.satoken.common.ResponseCode;
import com.example.satoken.common.ResponseResult;
import com.example.satoken.common.exception.BaseException;
import com.example.satoken.common.exception.GlobalsCustomExceptionMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.util.List;
import java.util.Set;

/**
 * 异常处理器
 *
 * @author WPZ
 * @since 2023-05-23
 */
@ControllerAdvice(annotations = BaseResponse.class)
@ResponseBody
@Slf4j
public class ExceptionHandlerAdvice {


    /**
     * SaToken异常
     *
     * @param e saToken异常
     * @return 统一响应体
     */
    @ExceptionHandler({SaTokenException.class})
    public ResponseResult saTokenException(SaTokenException e) {
        log.error("SaTokenException: {}", e.getMessage(), e);
        return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(), ResponseCode.SERVICE_ERROR.getMsg());
    }


    /**
     * SaToken异常
     *
     * @param e saToken异常
     * @return 统一响应体
     */
    @ExceptionHandler({NotLoginException.class})
    public ResponseResult notLoginException(NotLoginException e) {
        log.error("NotLoginException: {}", e.getMessage(), e);
        // 未登录的LOG_OUT
        return new ResponseResult(ResponseCode.LOG_OUT.getCode(), ResponseCode.LOG_OUT.getMsg());
    }

    /**
     * 枚举类序列化异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler({HttpMessageNotReadableException.class, IllegalArgumentException.class, IllegalStateException.class})
    public ResponseResult IllegalArgumentException(HttpMessageNotReadableException e) throws IOException {
        log.error(e.getMessage(), e);
        return new ResponseResult(ResponseCode.VALID_ENUM.getCode(), ResponseCode.VALID_ENUM.getMsg());
    }


    /**
     * validation 的全局异常处理器
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        Set<String> messages = CollUtil.newHashSet();
        for (FieldError fieldError : fieldErrors) {
            messages.add("【"+fieldError.getField().concat("->").concat(fieldError.getDefaultMessage()+"】"));
        }
        return new ResponseResult(800, CollUtil.join(messages, ","));
    }

    /**
     * 处理业务异常BaseException（自定义异常）
     *
     * @param e 业务异常
     * @return 统一响应体
     */
    @ExceptionHandler(BaseException.class)
    public ResponseResult handleBaseException(BaseException e) {
        log.error(e.getMessage(), e);
        GlobalsCustomExceptionMessage code = e.getCode();
        return new ResponseResult(code.getCode(), code.getMsg());
    }


    /**
     * 处理未捕获的RuntimeException
     *
     * @param e 运行时异常
     * @return 统一响应体
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseResult handleRuntimeException(RuntimeException e) {
        log.error(e.getMessage(), e);
        return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(), ResponseCode.SERVICE_ERROR.getMsg());
    }

    /**
     * 处理未捕获的Exception
     *
     * @param e 异常
     * @return 统一响应体
     */
    @ExceptionHandler(Exception.class)
    public ResponseResult handleException(Exception e) {
        log.error(e.getMessage(), e);
        return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(), ResponseCode.SERVICE_ERROR.getMsg());
    }


}
